<?php
/************************************
*   新浪相册 7.0
*   @file:lib_memcached.php
*   @intro:
*   @author:shaopu@
*   @date:Mon Nov 24 16:00:30 CST 2008
************************************/

class lib_memcached
{
    private $_config = array();     //mc配置
    private $_mc;                   //memcached实例
    private $_connects = array();   //连接池
    
    public function __construct($config)
    {
        $this->_mc = new Memcached();
        //开启一致性哈希
        $this->_mc->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT); 
        //使用KETAMA哈希算法
        $this->_mc->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE  , true);
        //默认已开启数据压缩，所以不用设置
        //$this->_mc->setOption(Memcached::OPT_COMPRESSION  , true);
        
        
        $this->_config = $config;
        foreach ($this->_config as $v)
        {
            list($host , $port) = explode(':' , $v);
            $this->_mc->addServer($host , $port);
        }
    }
    
    /**
     * 记出错LOG,只用作调试
     *
     * @param 当前调用的方法名 $func
     * @param string $content
     * @return true
     */
    private function _log($func , $content)
    {
        K_log::debug(__CLASS__ , $func .TAB. $content);
        return true;
    }
    /**
     * 取MEMCACHED操作返回结果标识
     *
     * @return int
     */
    private function _result()
    {
        return $this->_mc->getResultCode();
    }
    private function _get_host_by_hash_key($hash_key)
    {
        $config = $this->_mc->getServerByKey($hash_key);
        return implode(':' , $config);
    }
    /**
     * 取一条记录
     *
     * @param string $key   键   
     * @param mix $value
     * @param string $hash_key  用来哈希服务器的数据　常用UID
     * @return bool
     */
    public function get($key , &$value , $hash_key = null)
    {
        $hash_key = is_null($hash_key) ? $key : $hash_key;
        $value = $this->_mc->getByKey($hash_key , $key);    //getByKey 第一个参数就是用来定位服务器的
        
        $rs = $this->_result();
        if($rs == Memcached::RES_SUCCESS)
            return true;
        else 
        {
            //如果不是数据找不到错误　就报警
            if($rs <> Memcached::RES_NOTFOUND)
                K_log::alert(K5_LOG_ALERT_MC , $this->_get_host_by_hash_key($hash_key) , 'get_err '.$rs);
                
            $this->_log(__FUNCTION__ , 'getByKey '.$key.' e:'.$rs);
            return false;
        }
    }
    
    /**
     * 取多条记录
     *
     * @param array $aKeys  多个键
     * @param mix $value
     * @param string $hash_key  哈希服务器用　常用UID　
     * @return bool 
     */
    public function get_multi($aKeys , &$value , $hash_key = null)
    {
        if(!is_array($aKeys))
            return false;

        if(is_null($hash_key))
            $value = $this->_mc->getMulti($aKeys);
        else 
            $value = $this->_mc->getMultiByKey($hash_key , $aKeys);
        /*
            此时如果多台MC中有个别死掉的，getResultCode　也会返回成功，所以不能作为成功标准。
            还是在应用层看数据是否存在进行验证
        */
        return true;
    }
    
    /**
     * 设置一条记录
     *
     * @param string $key
     * @param mix $value
     * @param string $hash_key
     * @return bool
     */
    public function set($key , $value , $hash_key = null , $expire = 0)
    {
        
        $hash_key = is_null($hash_key) ? $key : $hash_key;
        $rs = $this->_mc->setByKey($hash_key , $key , $value);
        if(!$rs)
        {
            K_log::alert(K5_LOG_ALERT_MC , $this->_get_host_by_hash_key($hash_key) , 'set_err e:'.$this->_result());
            $this->_log(__FUNCTION__ , 'setByKey '.$key.' e:'.$this->_result());
        }
            
        return $rs;
    }
    
    /**
     * 删除一条记录
     *
     * @param string $key
     * @param string $hash_key
     * @return bool
     */
    public function delete($key , $hash_key = null)
    {
        $hash_key = is_null($hash_key) ? $key : $hash_key;
        $rs = $this->_mc->deleteByKey($hash_key , $key);
        if(!$rs)
        {
            if($this->_result() <> Memcached::RES_NOTFOUND)
                K_log::alert(K5_LOG_ALERT_MC , $this->_get_host_by_hash_key($hash_key) , 'del_err');
            $this->_log(__FUNCTION__ , 'deleteByKey '.$key.' e:'.$this->_result());
        }
        return $rs;
    }
    
    
    
    /**
     * 累加操作
     * 注意！  本操作无法设定根据什么值进行哈希服务器，而只能使用KEY进行哈希
     * 目前只用作MDB如评论数、点击数的操作
     *
     * @param string $key
     * @param int $n
     * @return bool
     */
    public function increment($key , $n = 1)
    {
        $rs = $this->_mc->increment($key , (int)$n);
        if(!$rs)
        {
            $error = $this->_result();
            if($error == Memcached::RES_NOTFOUND)
            {
                $rs = $this->_mc->set($key , 1);
                if(!$rs)
                {
                    K_log::alert(K5_LOG_ALERT_MC , $this->_get_host_by_hash_key($key) , 'set_err'.$this->_result());
                    $this->_log(__FUNCTION__ , 'set '.$key.' e:'.$this->_result());
                }
            }
            else 
            {
                K_log::alert(K5_LOG_ALERT_MC , $this->_get_host_by_hash_key($key) , 'incr_err e:'.$error);
                $this->_log(__FUNCTION__ , 'increment '.$key.' e:'.$this->_result());
            }
            
        }    
        
            
        return true;
    }
    
    /**
     * 递减操作
     * 注意！  见increment操作
     *
     * @param string $key
     * @param int $n
     * @return bool
     */
    public function decrement($key , $n = 1)
    {
        $rs = $this->_mc->decrement($key , (int)$n);
        if(!$rs)
        {
            K_log::alert(K5_LOG_ALERT_MC , $this->_get_host_by_hash_key($key) , 'decr_err e:'.$this->_result());
            $this->_log(__FUNCTION__ , $key.' e:'.$this->_result());
        }
        return $rs;
    }
    
    
}
?>